#include "Timer.h"
#include "Atomic.h"
#include "StackAllocator.h"
#include "DoubleStackAllocator.h"
#include "PoolAllocator.h"
#include "HeapAllocator.h"
#include "Assertions.h"
#include "FilePath.h"
#include "Console.h"
#include "Logging.h"
#include "File.h"
#include "UnitTest.h"
#include "GlobalVariables.h"
#include "Constants.h"
#include "MemoryManager.h"
#include "FileSystem.h"
#include "Vector.h"
#include "LinkedList.h"
#include "Deque.h"
#include "Queue.h"
#include "BinarySearchTree.h"
#include "PriorityQueue.h"
#include "StringManager.h"
#include "Iterator.h"
#include "SystemManagement.h"

#include "TestFunctions.h"

#include <cstdio>
#include <fstream>
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <windows.h>
#include <signal.h>

using namespace CEngine;

int main(int argc, char* argv[])
{
    startupSystems();

    runUnitTests();

    /*Deque<Test> con1(100);

    Iterator<Test> it1(con1.begin());
    Iterator<Test> it2(con1.begin());
    it1[10];
    it2[91];

    LinkedList<Test> con2(it1, it2);

    U32 count = 0;
    for (Iterator<Test> it = con2.rBegin(); it != con2.end(); --it) {
        Console::print("%u\t%u\n", ++count, (*it).value1);
    }*/

    system("cls");

    Timer timer;
    I64 stdAddA = 0, stdAccessA = 0, stdDeleteA = 0;
    I64 ceAddA = 0, ceAccessA = 0, ceDeleteA = 0;

    U64 elements = 100000;
    U64 cycles = 1000;
    for (U64 i = 0; i < cycles; ++i) {
        I64 stdAdd, stdAccess, stdDelete;
        I64 ceAdd, ceAccess, ceDelete;
        {
             std::deque<U64> vect;

             timer.startTimer();
             for (U64 i = 0; i < elements; ++i) {
                 vect.push_back(555);
             }
             stdAdd = timer.getTicks();

             timer.resetTimer();
             for (auto c = vect.begin(); c != vect.end(); ++c) {
                 *c = i;
             }
             stdAccess = timer.getTicks();

             timer.resetTimer();
             while(!vect.empty()) {
                vect.pop_back();
             }
             stdDelete = timer.getTicks();
        }

        //gotoXY(0,0);
        //MemoryManager::printMemoryUsage();

        {
             Deque<U64> vect;

             timer.startTimer();
             for (U64 i = 0; i < elements; ++i) {
                 vect.pushBack(555);
             }
             ceAdd = timer.getTicks();

             //gotoXY(0,0);
             //MemoryManager::printMemoryUsage();

             U64 temp;
             timer.resetTimer();
             for (Iterator<U64> it = vect.begin(); it != vect.end(); ++it) {
                 *it = i;
             }
             ceAccess = timer.getTicks();

             timer.resetTimer();
             while(!vect.isEmpty()) {
                vect.popBack();
             }
             ceDelete = timer.getTicks();
        }

        //gotoXY(0,0);
        //MemoryManager::printMemoryUsage();

        stdAddA += stdAdd;
        stdAccessA += stdAccess;
        stdDeleteA += stdDelete;
        ceAddA += ceAdd;
        ceAccessA += ceAccess;
        ceDeleteA += ceDelete;

        Console::print("%d\r", i);
    }
    stdAddA /= cycles;
    stdAccessA /= cycles;
    stdDeleteA /= cycles;
    ceAddA /= cycles;
    ceAccessA /= cycles;
    ceDeleteA /= cycles;

    Console::print("std: %lld add, %lld access, %lld delete\n", stdAddA, stdAccessA, stdDeleteA);
    Console::print("cen: %lld add, %lld access, %lld delete\n", ceAddA, ceAccessA, ceDeleteA);

    shutdownSystems();
}
